<?php

namespace app;


/**
 * Class Request
 * @package app
 */
class Request extends \think\Request
{
    

    /**
     * 不过滤变量名
     * @var array
     */
    protected $except = [
		'menu_path', 'api_url', 'unique_auth',
		'description', 'custom_form', 'product_detail_diy', 'value', 'member', 'product_category_diy'
	];


	/**
	 * 获取请求的数据
	 * @param array $params
	 * @param bool $suffix
	 * @param bool $filter
	 * @return array
	 */
	public function more(array $params, bool $suffix = false, bool $filter = true): array
	{
		$p = [];
		$i = 0;
		foreach ($params as $param) {
			if (!is_array($param)) {
				$p[$suffix == true ? $i++ : $param] = $this->param($param);
			} else {
				if (!isset($param[1])) $param[1] = null;
				if (!isset($param[2])) $param[2] = '';
				if (is_array($param[0])) {
					$name = is_array($param[1]) ? $param[0][0] . '/a' : $param[0][0] . '/' . $param[0][1];
					$keyName = $param[0][0];
				} else {
					$name = is_array($param[1]) ? $param[0] . '/a' : $param[0];
					$keyName = $param[0];
				}

				$p[$suffix == true ? $i++ : ($param[3] ?? $keyName)] = $this->param($name, $param[1], $param[2]);
			}
		}

		if ($filter && $p) {
			$p = $this->filterArrayValues($p);
		}

		return $p;
	}

	/**
	 * @param $array
	 * @return array
	 */
	public function filterArrayValues($array)
	{
		$result = [];
		foreach ($array as $key => $value) {
			if (is_array($value)) {
				// 如果值是数组，递归调用 filterArrayValues
				$result[$key] = in_array($key, $this->except) ? $value : $this->filterArrayValues($value);
			} else {
				if (in_array($key, $this->except) || is_int($value) || is_null($value)) {
					$result[$key] = $value;
				} else {
					// 如果值是字符串，过滤特殊字符
					$result[$key] = $this->filter_str($value);
				}

			}
		}
		return $result;
	}


    /**
     * 获取get参数
     * @param array $params
     * @param bool $suffix
     * @param bool $filter
     * @return array
     */
    public function getMore(array $params, bool $suffix = false, bool $filter = true): array
    {
        return $this->more($params, $suffix, $filter);
    }

    /**
     * 获取post参数
     * @param array $params
     * @param bool $suffix
     * @param bool $filter
     * @return array
     */
    public function postMore(array $params, bool $suffix = false, bool $filter = true): array
    {
        return $this->more($params, $suffix, $filter);
    }

    /**
     * 获取用户访问端
     * @return array|string|null
     */
    public function getFromType()
    {
        return $this->header('Form-type', '');
    }

    /**
     * 当前访问端
     * @param string $terminal
     * @return bool
     */
    public function isTerminal(string $terminal)
    {
        return strtolower($this->getFromType()) === $terminal;
    }

    /**
     * 是否是H5端
     * @return bool
     */
    public function isH5()
    {
        return $this->isTerminal('h5');
    }

    /**
     * 是否是微信端
     * @return bool
     */
    public function isWechat()
    {
        return $this->isTerminal('wechat');
    }

    /**
     * 是否是小程序端
     * @return bool
     */
    public function isRoutine()
    {
        return $this->isTerminal('routine');
    }

    /**
     * 是否是app端
     * @return bool
     */
    public function isApp()
    {
        return $this->isTerminal('app');
    }

    /**
     * 是否是app端
     * @return bool
     */
    public function isPc()
    {
        return $this->isTerminal('pc');
    }

    /**
     * 获取ip
     * @return string
     */
    public function ip(): string
    {
        if ($this->server('HTTP_CLIENT_IP', '')) {
            $ip = $this->server('HTTP_CLIENT_IP', '');
        } elseif ($this->server('HTTP_X_REAL_IP', '')) {
            $ip = $this->server('HTTP_X_REAL_IP', '');
        } elseif ($this->server('HTTP_X_FORWARDED_FOR', '')) {
            $ip = $this->server('HTTP_X_FORWARDED_FOR', '');
            $ips = explode(',', $ip);
            $ip = $ips[0];
        } elseif ($this->server('REMOTE_ADDR', '')) {
            $ip = $this->server('REMOTE_ADDR', '');
        } else {
            $ip = '0.0.0.0';
        }
        return $ip;
    }

   private function attr_format($arr)
    {
        $data = [];
        $res = [];
        $count = count($arr);
        if ($count > 1) {
            for ($i = 0; $i < $count - 1; $i++) {
                if ($i == 0) $data = $arr[$i]['detail'];
                //替代变量1
                $rep1 = [];
                foreach ($data as $v) {
                    foreach ($arr[$i + 1]['detail'] as $g) {
                        //替代变量2
                        $rep2 = ($i != 0 ? '' : $arr[$i]['value'] . '_$_') . $v . '-$-' . $arr[$i + 1]['value'] . '_$_' . $g;
                        $tmp[] = $rep2;
                        if ($i == $count - 2) {
                            foreach (explode('-$-', $rep2) as $k => $h) {
                                //替代变量3
                                $rep3 = explode('_$_', $h);
                                //替代变量4
                                $rep4['detail'][$rep3[0]] = isset($rep3[1]) ? $rep3[1] : '';
                            }
                            if($count == count($rep4['detail']))
                                $res[] = $rep4;
                        }
                    }
                }
                $data = isset($tmp) ? $tmp : [];
            }
        } else {
            $dataArr = [];
            foreach ($arr as $k => $v) {
                foreach ($v['detail'] as $kk => $vv) {
                    $dataArr[$kk] = $v['value'] . '_' . $vv;
                    $res[$kk]['detail'][$v['value']] = $vv;
                }
            }
            $data[] = implode('-', $dataArr);
        }
        return [$data, $res];
    }

   private function filter_str($str)
	{
		$rules = [
			'/\.\./', // 禁用包含 ../ 的参数
			'/\<\?/', // 禁止 php 脚本出现
			'/\bor\b.*=.*/i', // 匹配 'or 1=1'，防止 SQL 注入（注意边界词 \b 和不区分大小写 i 修饰符）
			'/(select[\s\S]*?)(from|limit)/i', // 防止 SQL 注入
			'/(union[\s\S]*?select)/i', // 防止 SQL 注入
			'/(having|updatexml|extractvalue)/i', // 防止 SQL 注入
			'/sleep\((\s*)(\d*)(\s*)\)/i', // 防止 SQL 盲注
			'/benchmark\((.*)\,(.*)\)/i', // 防止 SQL 盲注
			'/base64_decode\(/i', // 防止 SQL 变种注入
			'/(?:from\W+information_schema\W)/i', // 注意这里的 (?:...) 是不合法的，应该是 (?:...) 表示非捕获组，但通常我们不需要这个
			'/(?:current_|user|database|schema|connection_id)\s*\(/i', // 防止 SQL 注入（注意去掉了不必要的 (?:...)）
			'/(?:etc\/\W*passwd)/i', // 防止窥探 Linux 用户信息
			'/into(\s+)(?:dump|out)file\s*/i', // 禁用 MySQL 导出函数
			'/group\s+by.+\(/i', // 防止 SQL 注入
			'/(?:define|eval|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|preg_\w+|execute|echo|print|print_r|var_dump|(fp)open|alert|showmodaldialog)\(/i', // 禁用 webshell 相关某些函数
			'/(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\:\/\//i', // 防止一些协议攻击（注意协议后的三个斜杠）
			'/\$_(GET|POST|COOKIE|FILES|SESSION|ENV|GLOBALS|SERVER)\[/i', // 禁用一些内置变量，注意 PHP 变量名通常是大写的
			'/<(iframe|script|body|img|layer|div|meta|style|base|object|input)/i', // 防止 XSS 标签植入
			'/(onmouseover|onerror|onload|onclick)\=/i', // 防止 XSS 事件植入
			'/\|\|.*?(?:ls|pwd|whoami|ll|ifconfig|ipconfig|&&|chmod|cd|mkdir|rmdir|cp|mv)/i', // 防止执行 shell（注意去掉了不合适的 ifconfog）
			'/\sand\s+.*=.*/i' // 匹配 and 1=1
		];
		if (filter_var($str, FILTER_VALIDATE_URL)) {
			$url = parse_url($str);
			if (!isset($url['scheme'])) return $str;
			$host = $url['scheme'] . '://' . $url['host'];
			$str = $host . preg_replace($rules, '', str_replace($host, '', $str));
		} else {
			$str = preg_replace($rules, '', $str);
		}
		return $str;
	}
}
